define(
[
    "render/BufferMaker",
    "render/static/StaticRenderBatch",
    "render/pick/PickRenderBatch",
    "render/poi/POIRenderer",
    "framework/graphic/WebGL",
    "framework/math/GLMatrix"
],
function(BufferMaker, StaticRenderBatch, PickRenderBatch, POIRenderer, WebGL) {
    return {
        create: function() {

            var _self = {
                init: function(systemMgr) {
                    _systemMgr = systemMgr;
                    _posBufMk = BufferMaker.create(WebGL.gl.ARRAY_BUFFER, Float32Array, 3);
                    _norBufMk = BufferMaker.create(WebGL.gl.ARRAY_BUFFER, Float32Array, 3);
                    _ccdBufMk = BufferMaker.create(WebGL.gl.ARRAY_BUFFER, Float32Array, 3);
                    _indBufMk = BufferMaker.create(WebGL.gl.ELEMENT_ARRAY_BUFFER, Uint16Array, 1);
                    _lineIndBufMk = BufferMaker.create(WebGL.gl.ELEMENT_ARRAY_BUFFER, Uint16Array, 1);
                    _visibleBufMk = BufferMaker.create(WebGL.gl.ARRAY_BUFFER, Float32Array, 1);

                    _pickBatch = PickRenderBatch.create();

                    return this;
                },

                createRenderer: function(data) {
                    var processed = data.visual;
                    return _addUnit(
                        processed.pos, processed.indices, 
                        processed.lineIndices, processed.normals
                    );
                },

                finalize: function() {
                    //Flush VBOs
                    _posBufMk.flush();
                    _norBufMk.flush();
                    _ccdBufMk.flush();
                    _indBufMk.flush();
                    _visibleBufMk.flush();
                    _lineIndBufMk.flush();

                    //Create render batch
                    _renderBatch = StaticRenderBatch.create().init(
                        _systemMgr,
                        _posBufMk.getBuffer(),
                        _norBufMk.getBuffer(), 
                        _ccdBufMk.getBuffer(),
                        _indBufMk.getBuffer(),
                        _visibleBufMk.getBuffer(),
                        _lineIndBufMk.getBuffer()
                    );

                    //Create pick batch
                    _pickBatch.init(
                        _systemMgr,
                        _posBufMk.getBuffer(),
                        _ccdBufMk.getBuffer(),
                        _indBufMk.getBuffer(),
                        _visibleBufMk.getBuffer()
                    )
                },

                getMark: function() {
                    return {
                        tri: _indBufMk.getNumItems(),
                        line: _lineIndBufMk.getNumItems()
                    };
                },

                setDrawUntilMark: function(mark) {
                    if(mark) {
                        _renderBatch.setLineDrawConf(0, mark.line);
                        _renderBatch.setTriDrawConf(0, mark.tri);
                    }
                    else 
                        _renderBatch.toDefaultConf();
                },

                destroy: function() {
                    _renderBatch.destroy();
                    _pickBatch.destroy();

                    _posBufMk.destroy();
                    _ccdBufMk.destroy();
                    _norBufMk.destroy();
                    _indBufMk.destroy();
                    _visibleBufMk.destroy();
                    _lineIndBufMk.destroy();
                },

                setVisible: function(val) {
                    _renderBatch.setVisible(val);
                    _pickBatch.setEnable(val);
                }
            };


            //Buffers
            var _posBufMk;
            var _indBufMk;
            var _ccdBufMk; //color code
            var _lineIndBufMk;
            var _norBufMk;
            var _visibleBufMk;

            //Managers
            var _systemMgr;
            var _renderBatch;
            var _pickBatch;

            function _addUnit(pos, indices, lineIndices, normals) {
                //Add indices
                var numItems = _posBufMk.getNumItems();
                var bufIndUnit = _indBufMk.add(indices.map(function(val){
                    return val + numItems;
                }));
                var bufLineIndUnit = _lineIndBufMk.add(lineIndices.map(function(val){
                    return val + numItems;
                }));

                //Add position
                var bufPosUnit = _posBufMk.add(pos);

                //Add normal
                var bufNorUnit = _norBufMk.add(normals);

                //Compute number of added vertex
                numItems = _posBufMk.getNumItems() - numItems;

                //Add visible
                var visibleData = [];
                for(var i = 0; i < numItems; ++i) {
                    visibleData[i] = 1; //Default: visible
                }
                var bufVisibleUnit = _visibleBufMk.add(visibleData);

                //Add color code
                var pickUnit = _pickBatch.fetchColorUnit();
                var color = pickUnit.colorCode;
                var allColor = [];
                for(var i = 0; i < numItems; ++i) {
                    color.forEach(function(val){allColor.push(val);});
                }
                _ccdBufMk.add(allColor);

                return POIRenderer.create().init(
                    bufPosUnit, bufIndUnit, pickUnit, bufVisibleUnit,
                    _calculateCenterPos(pos)
                );
            }

            function _calculateCenterPos(pos) {
                //Init
                var sum = [0, 0, 0];

                //Sum
                for(var i = 0; i < pos.length; i+=3) {
                    sum[0] += pos[i+0];
                    sum[1] += pos[i+1];
                    sum[2] += pos[i+2];
                }

                //Average
                var count = pos.length/3;
                sum[0] /= count;
                sum[1] /= count;
                sum[2] /= count;

                //Return
                return vec3.create(sum);
            }

            return _self;
        }
    };
}
);